#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
日志配置和错误处理模块

提供统一的日志管理和异常处理机制
"""

import logging
import logging.handlers
import os
import sys
import traceback
from datetime import datetime
from typing import Optional, Dict, Any
from functools import wraps
import json

class ColoredFormatter(logging.Formatter):
    """彩色日志格式器"""
    
    # ANSI颜色代码
    COLORS = {
        'DEBUG': '\033[36m',    # 青色
        'INFO': '\033[32m',     # 绿色
        'WARNING': '\033[33m',  # 黄色
        'ERROR': '\033[31m',    # 红色
        'CRITICAL': '\033[35m', # 紫色
        'RESET': '\033[0m'      # 重置
    }
    
    def format(self, record):
        # 获取原始格式化结果
        formatted = super().format(record)
        
        # 添加颜色
        color = self.COLORS.get(record.levelname, self.COLORS['RESET'])
        reset = self.COLORS['RESET']
        
        return f"{color}{formatted}{reset}"

class JsonFormatter(logging.Formatter):
    """JSON格式日志格式器"""
    
    def format(self, record):
        log_entry = {
            'timestamp': datetime.fromtimestamp(record.created).isoformat(),
            'level': record.levelname,
            'logger': record.name,
            'message': record.getMessage(),
            'module': record.module,
            'function': record.funcName,
            'line': record.lineno
        }
        
        # 添加异常信息
        if record.exc_info:
            log_entry['exception'] = {
                'type': record.exc_info[0].__name__,
                'message': str(record.exc_info[1]),
                'traceback': traceback.format_exception(*record.exc_info)
            }
        
        # 添加额外字段
        if hasattr(record, 'extra_data'):
            log_entry['extra'] = record.extra_data
        
        return json.dumps(log_entry, ensure_ascii=False)

class LoggerManager:
    """日志管理器"""
    
    def __init__(self, log_dir: str = "logs"):
        self.log_dir = log_dir
        self.loggers: Dict[str, logging.Logger] = {}
        
        # 确保日志目录存在
        os.makedirs(log_dir, exist_ok=True)
    
    def setup_logger(self, 
                    name: str,
                    level: str = "INFO",
                    console_output: bool = True,
                    file_output: bool = True,
                    json_format: bool = False,
                    max_file_size: int = 10 * 1024 * 1024,  # 10MB
                    backup_count: int = 5) -> logging.Logger:
        """设置日志器"""
        
        if name in self.loggers:
            return self.loggers[name]
        
        logger = logging.getLogger(name)
        logger.setLevel(getattr(logging, level.upper(), logging.INFO))
        
        # 清除现有处理器
        for handler in logger.handlers[:]:
            logger.removeHandler(handler)
        
        # 控制台处理器
        if console_output:
            console_handler = logging.StreamHandler(sys.stdout)
            if json_format:
                console_formatter = JsonFormatter()
            else:
                console_formatter = ColoredFormatter(
                    '%(asctime)s - %(name)s - %(levelname)s - %(message)s',
                    datefmt='%Y-%m-%d %H:%M:%S'
                )
            console_handler.setFormatter(console_formatter)
            logger.addHandler(console_handler)
        
        # 文件处理器
        if file_output:
            log_file = os.path.join(self.log_dir, f"{name}.log")
            file_handler = logging.handlers.RotatingFileHandler(
                log_file,
                maxBytes=max_file_size,
                backupCount=backup_count,
                encoding='utf-8'
            )
            
            if json_format:
                file_formatter = JsonFormatter()
            else:
                file_formatter = logging.Formatter(
                    '%(asctime)s - %(name)s - %(levelname)s - %(funcName)s:%(lineno)d - %(message)s',
                    datefmt='%Y-%m-%d %H:%M:%S'
                )
            file_handler.setFormatter(file_formatter)
            logger.addHandler(file_handler)
        
        # 错误日志单独文件
        error_log_file = os.path.join(self.log_dir, f"{name}_error.log")
        error_handler = logging.handlers.RotatingFileHandler(
            error_log_file,
            maxBytes=max_file_size,
            backupCount=backup_count,
            encoding='utf-8'
        )
        error_handler.setLevel(logging.ERROR)
        
        if json_format:
            error_formatter = JsonFormatter()
        else:
            error_formatter = logging.Formatter(
                '%(asctime)s - %(name)s - %(levelname)s - %(funcName)s:%(lineno)d - %(message)s\n%(exc_text)s',
                datefmt='%Y-%m-%d %H:%M:%S'
            )
        error_handler.setFormatter(error_formatter)
        logger.addHandler(error_handler)
        
        # 防止日志传播到根日志器
        logger.propagate = False
        
        self.loggers[name] = logger
        return logger
    
    def get_logger(self, name: str) -> Optional[logging.Logger]:
        """获取日志器"""
        return self.loggers.get(name)
    
    def log_with_extra(self, logger_name: str, level: str, message: str, extra_data: Dict[str, Any] = None):
        """记录带额外数据的日志"""
        logger = self.get_logger(logger_name)
        if logger:
            record = logger.makeRecord(
                logger.name, getattr(logging, level.upper()), 
                '', 0, message, (), None
            )
            if extra_data:
                record.extra_data = extra_data
            logger.handle(record)

class ErrorHandler:
    """错误处理器"""
    
    def __init__(self, logger: logging.Logger):
        self.logger = logger
        self.error_counts: Dict[str, int] = {}
    
    def handle_exception(self, exc: Exception, context: str = "", extra_data: Dict[str, Any] = None) -> str:
        """处理异常"""
        error_type = type(exc).__name__
        error_message = str(exc)
        
        # 统计错误次数
        error_key = f"{error_type}:{error_message}"
        self.error_counts[error_key] = self.error_counts.get(error_key, 0) + 1
        
        # 构建错误信息
        full_message = f"{context}: {error_message}" if context else error_message
        
        # 记录日志
        self.logger.error(
            f"[{error_type}] {full_message}",
            exc_info=True,
            extra={'error_count': self.error_counts[error_key], 'extra_data': extra_data}
        )
        
        return full_message
    
    def get_error_statistics(self) -> Dict[str, int]:
        """获取错误统计"""
        return self.error_counts.copy()
    
    def reset_error_counts(self):
        """重置错误计数"""
        self.error_counts.clear()

def log_execution_time(logger: logging.Logger):
    """记录函数执行时间的装饰器"""
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            start_time = datetime.now()
            try:
                result = func(*args, **kwargs)
                end_time = datetime.now()
                execution_time = (end_time - start_time).total_seconds()
                logger.info(f"{func.__name__} 执行完成，耗时: {execution_time:.2f}秒")
                return result
            except Exception as e:
                end_time = datetime.now()
                execution_time = (end_time - start_time).total_seconds()
                logger.error(f"{func.__name__} 执行失败，耗时: {execution_time:.2f}秒，错误: {str(e)}")
                raise
        return wrapper
    return decorator

def retry_on_error(max_retries: int = 3, delay: float = 1.0, logger: logging.Logger = None):
    """错误重试装饰器"""
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            last_exception = None
            
            for attempt in range(max_retries + 1):
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    last_exception = e
                    
                    if logger:
                        logger.warning(
                            f"{func.__name__} 第 {attempt + 1} 次尝试失败: {str(e)}"
                        )
                    
                    if attempt < max_retries:
                        import time
                        time.sleep(delay * (2 ** attempt))  # 指数退避
                    else:
                        if logger:
                            logger.error(
                                f"{func.__name__} 重试 {max_retries} 次后仍然失败",
                                exc_info=True
                            )
                        raise last_exception
            
            raise last_exception
        return wrapper
    return decorator

def safe_execute(func, *args, default_return=None, logger: logging.Logger = None, **kwargs):
    """安全执行函数"""
    try:
        return func(*args, **kwargs)
    except Exception as e:
        if logger:
            logger.error(f"安全执行 {func.__name__} 失败: {str(e)}", exc_info=True)
        return default_return

class PerformanceMonitor:
    """性能监控器"""
    
    def __init__(self, logger: logging.Logger):
        self.logger = logger
        self.metrics: Dict[str, list] = {}
    
    def record_metric(self, name: str, value: float, unit: str = ""):
        """记录性能指标"""
        if name not in self.metrics:
            self.metrics[name] = []
        
        self.metrics[name].append({
            'value': value,
            'timestamp': datetime.now().isoformat(),
            'unit': unit
        })
        
        self.logger.debug(f"性能指标 {name}: {value} {unit}")
    
    def get_metrics_summary(self, name: str) -> Dict[str, Any]:
        """获取指标摘要"""
        if name not in self.metrics or not self.metrics[name]:
            return {}
        
        values = [m['value'] for m in self.metrics[name]]
        
        return {
            'count': len(values),
            'min': min(values),
            'max': max(values),
            'avg': sum(values) / len(values),
            'latest': values[-1],
            'unit': self.metrics[name][-1]['unit']
        }
    
    def log_metrics_summary(self):
        """记录所有指标摘要"""
        for name in self.metrics:
            summary = self.get_metrics_summary(name)
            if summary:
                self.logger.info(
                    f"指标 {name}: 次数={summary['count']}, "
                    f"最小值={summary['min']}, 最大值={summary['max']}, "
                    f"平均值={summary['avg']:.2f}, 最新值={summary['latest']} {summary['unit']}"
                )

# 全局日志管理器实例
_logger_manager = LoggerManager()

def get_logger(name: str, **kwargs) -> logging.Logger:
    """获取或创建日志器"""
    logger = _logger_manager.get_logger(name)
    if logger is None:
        logger = _logger_manager.setup_logger(name, **kwargs)
    return logger

def setup_application_logging(log_level: str = "INFO", 
                             log_dir: str = "logs",
                             json_format: bool = False):
    """设置应用程序日志"""
    global _logger_manager
    _logger_manager = LoggerManager(log_dir)
    
    # 设置主要组件的日志器
    loggers_config = {
        'main': {'level': log_level, 'console_output': True, 'file_output': True},
        'database': {'level': log_level, 'console_output': False, 'file_output': True},
        'importer': {'level': log_level, 'console_output': False, 'file_output': True},
        'crawler': {'level': log_level, 'console_output': False, 'file_output': True},
        'scheduler': {'level': log_level, 'console_output': False, 'file_output': True},
    }
    
    for name, config in loggers_config.items():
        _logger_manager.setup_logger(name, json_format=json_format, **config)
    
    # 设置根日志器以捕获未分类的日志
    root_logger = logging.getLogger()
    root_logger.setLevel(getattr(logging, log_level.upper(), logging.INFO))
    
    return _logger_manager

if __name__ == "__main__":
    # 测试日志配置
    setup_application_logging("DEBUG")
    
    logger = get_logger("test")
    error_handler = ErrorHandler(logger)
    monitor = PerformanceMonitor(logger)
    
    # 测试日志记录
    logger.info("这是一条信息日志")
    logger.warning("这是一条警告日志")
    
    # 测试错误处理
    try:
        raise ValueError("测试错误")
    except Exception as e:
        error_handler.handle_exception(e, "测试上下文")
    
    # 测试性能监控
    monitor.record_metric("test_metric", 1.23, "秒")
    monitor.record_metric("test_metric", 2.45, "秒")
    monitor.log_metrics_summary()
    
    print("日志配置测试完成")